#include <stdio.h>
#include <stdint.h>

static uint16_t modbus_crc16(uint8_t *buf_data, uint16_t buf_len) {
  uint16_t TCPCRC = 0xffff;
  uint16_t POLYNOMIAL = 0xa001;
  uint8_t i, j;

  for (i = 0; i < buf_len; i++) {
    TCPCRC ^= buf_data[i];
    for (j = 0; j < 8; j++) {
      if ((TCPCRC & 0x0001) != 0) {
        TCPCRC >>= 1;
        TCPCRC ^= POLYNOMIAL;
      } else {
        TCPCRC >>= 1;
      }
    }
  }

  return TCPCRC;
}

static uint16_t modbus_crc16_msb_lsb(uint8_t *buf_data, uint16_t buf_len) {
  uint16_t TCPCRC = 0xffff;
  uint16_t POLYNOMIAL = 0xa001;
  uint8_t i, j;

  for (i = 0; i < buf_len; i++) {
    TCPCRC ^= buf_data[i];
    for (j = 0; j < 8; j++) {
      if ((TCPCRC & 0x0001) != 0) {
        TCPCRC >>= 1;
        TCPCRC ^= POLYNOMIAL;
      } else {
        TCPCRC >>= 1;
      }
    }
  }

  uint8_t crc_lsb = (uint8_t)(TCPCRC & 0x00FF);
  uint8_t crc_msb = (uint8_t)(TCPCRC >> 8);
  TCPCRC = (crc_lsb << 8) | crc_msb;  // 低位在前，高位在后, 大端模式
  return TCPCRC;
}

uint16_t bit16_ltoh(uint16_t data) {
  return (data << 8 & 0xff00) | (data >> 8 & 0x00ff);
}


int main(int argc, char const *argv[])
{
  /* code */
  // uint8_t prase_data[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};
  // uint8_t prase_data[] = {0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x90, 0x0A};
  // uint8_t prase_data[] = {0x50, 0x03, 0x00, 0x49, 0x00, 0x04, 0x98, 0x5E};
  // uint8_t prase_data[] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x06, 0x94, 0x08};
  // uint8_t prase_data[] = {0x01, 0x03, 0x0C, 0x05, 0x02, 0x03, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x53};
  uint8_t prase_data[] = {0xC8, 0x03, 0x00, 0x01, 0x00, 0x01, 0xC4, 0x53};
  uint16_t prase_data_len = sizeof(prase_data) / sizeof(prase_data[0]);
  uint16_t crc16 = modbus_crc16(prase_data, prase_data_len - 2);
  uint16_t answer_crc16 = *(uint16_t*)(&prase_data[prase_data_len - 2]);
  printf("crc16: 0x%04X\n", crc16);
  printf("answer_crc16: 0x%04X\n", answer_crc16);
  // printf("crc16-lsb-msb: 0x%02X 0x%02X\n", (uint8_t)(crc16 & 0x00FF), (uint8_t)(crc16 >> 8));
  return 0;
}
